Плохо! Плохо!:  0
Страница 1 из 2 12 ПоследняяПоследняя
Показано с 1 по 10 из 11

Тема: [MZ] Что интересного можно делать с сохранениями

  1. #1
    Бывалый Аватар для Darchan Kaen
    Информация о пользователе
    Регистрация
    17.06.2013
    Адрес
    Одесса
    Сообщений
    851
    Записей в дневнике
    3
    Репутация: 47 Добавить или отнять репутацию

    По умолчанию [MZ] Что интересного можно делать с сохранениями

    Маленький туториал для MZ. Может кому-то будет полезно (особенно ввиду RTP-марафона).
    Если было - сорян, не нашел.

    На данный туториал меня "подбили" вопросы Скрипки и старая мысль, на что же способен мейкер без плагинов в контексте работы с внешними данными.


    Будет три части:
    I. Проверка наличия сохранений в принципе, получение кол-ва сохранений, удаление сохранений.
    II. Частичная загрузка сохранений.
    III. Лайфхак.

    Спойлер Первую часть для MV можно найти в Общих вопросах, в ответе на вопросы Скрипки:

    ...вторую часть, вероятно, тоже можно сделать - экспериментируйте.


    I. Проверка наличия сохранений в принципе, получение кол-ва сохранений, удаление сохранений.
    Относительно стандартные действия, которые могут пригодится в ряде случаев.

    Спойлер Проверка наличия сохранений в принципе, код для "Скрипта":

    Код:
    let isThereSaves = DataManager.isAnySavefileExists(); // вернет: true / false.
    $gameSwitches.setValue(1, isThereSaves); // если нужно записать есть/нет в переключатель №1.


    Спойлер Получение кол-ва сохранений, код для "Скрипта":

    Код:
    if( true === DataManager.isAnySavefileExists() ){
      const saveFilesList = DataManager._globalInfo;
      const savesFullCount = saveFilesList.length; //полный подсчет, с учетом пропусков (если сохранение в слотах 1 и 3, то выдаст что сохранений 3).
      const savesAccurateCount = saveFilesList.filter(save => save === save).length; //точный подсчет, с учетом пропусков (если сохранение в слотах 1 и 3, то выдаст что сохранений 2).
      $gameVariables.setValue(2, savesAccurateCount); // если нужно записать точное кол-во сохранений в переменную №2.
    }else{
      console.log('_isThereSaves: false');
    }


    Спойлер Удаление сохранений:

    Файл global.rmmzsave при этом не удаляется.
    Запуск кода ниже - исключительно на вашей ответственности.
    Спойлер На свой страх и риск, я предупреждал! Код для "Скрипта":

    Код:
    if( true === DataManager.isAnySavefileExists() ){
        const fs = require("fs"); const path = require('path');
        let base = path.dirname(process.mainModule.filename); let savePath = path.join(base, 'save/');
        const saveFilesCount = DataManager._globalInfo.length;
        for(let n = 0; n < saveFilesCount; n++){
          let currentSaveFilePath = savePath + DataManager.makeSavename(n) + '.rmmzsave'; console.log('_delete_currentSaveFilePath:', currentSaveFilePath);
          try{ fs.unlinkSync(currentSaveFilePath);
          }catch(error){ console.log('_error on deleting saves:', error); }
        } console.log('_delete_save_files_process: OK');
    }else{
      console.log('_isThereSaves: false');
    }



    II. Частичная загрузка сохранений.
    А вот тут интереснее, собственно ради этого я и создал данный мини-туториал.

    Как мы знаем, по-дефолту при сохранении в файл записываются переменные, переключатели, локальные переключатели и много чего еще.
    При загрузке, соответственно, это все выгружается и применяется мейкером.

    Конечно, для сохранения данных (переключателей, переменных, итд) во внешний файл есть ряд плагинов, но...
    Но что, если нужно чтоб мейкер выгрузил из "классического сохранения" данные, но их не применил?
    То есть, можно ли использовыать классический файл сохранения как внешний источних данных?

    Можно!
    Т.к. такую возможность, скорее всего, удобнее использовать часто, то запишем функцию загрузки внутрь переменной мейкера:

    Спойлер Код функции частичной загрузки данных, для "Скрипта":

    Смысл - вызывать функцию, указывая нужный слот сохранения, и записывать результат в отдельную переменную мейкера.
    Код:
    $gameVariables.setValue(N, (saveId) => {
      const saveName = DataManager.makeSavename(saveId);
    
      return StorageManager.loadZip(saveName)
            .then(zip => StorageManager.zipToJson(zip))
            .then(json => StorageManager.jsonToObject(json))
            .then(jsonObjs => $gameVariables.setValue(M, jsonObjs))
    		.catch( (error) => { console.log('_isThereSave: NO SAVE FILE #', saveId, ' ! ERROR:', error) } );
    });
    где:
    N - номер переменной, куда сохранили фунцию.
    M - номер переменной, куда запишется результат частичной загрузки данных.


    Как жы применить это? Сначала вызовем функцию.
    Спойлер Вызов частичной загрузки данных, для "Скрипта":

    Код:
    let halfLoader = $gameVariables.value(N);
    let halfLoadResult = halfLoader(I);
    где:
    N - номер переменной, куда сохранили фунцию.
    I - номер файла сохранения


    После этого лучше поставить комнду Ждать, на 5-15 кадров (я ставлю на 15).

    И, наконец, применение.
    А) Просто вывод на консоль (или что-то делать в "Скрипте").
    Спойлер Вызов частичной загрузки данных, для "Скрипта":

    Код:
    try{
    let halfLoadedData = $gameVariables.value(M);
    console.log( halfLoadedData.switches.value(X) ); // получение значения переключателя X из загруженных данных на консоль.
    }catch(error){ console.log('_ERROR, load result is:', error); }
    где:
    M - номер переменной, куда записался результат частичной загрузки данных.
    X - номер интересующего нас переключателя из сохранения.
    try{}catch(error){} - нужны для отлова ошибки в случае, если данные не загрузились (если такого быть не может, не пишите их).

    Б) Проверка в Условии
    Спойлер Вызов частичной загрузки данных, для Условия и скрипта в нем:

    Код:
    try{ 33 === $gameVariables.value(M).variables.value(Y); }catch(error){ false; } // получение значения переменной Y из загруженных данных и сравнения како-то числа с ней
    где:
    M - номер переменной, куда записался результат частичной загрузки данных.
    Y - номер интересующей нас переменной из сохранения.
    try{}catch(error){} - нужны для отлова ошибки в случае, если данные не загрузились (если такого быть не может, не пишите их).


    Конечно, это нужно в довольно редких случаях.
    Но если у вас игра, связанная с "зацикливанием", и вы хотите сохранять только промежуточные результаты - это один из вариантов.

    Вот перечень данных, которые можно достать из сохранения:
    Спойлер Название объекта и что содержит:

    Код:
        system // содержит то же, что и  $gameSystem
        screen; // содержит то же, что и  $gameScreen
        timer; // содержит то же, что и  $gameTimer
        switches; // содержит то же, что и  $gameSwitches
        variables; // содержит то же, что и  $gameVariables
        selfSwitches; // содержит то же, что и  $gameSelfSwitches
        actors; // содержит то же, что и  $gameActors
        party; // содержит то же, что и  $gameParty
        map; // содержит то же, что и  $gameMap
        player;// содержит то же, что и  $gamePlayer



    III. Лайфхак.
    Лайфхак относится к частичной загрузке сохранений.
    Например, мы используем такой фокус и не хотим, что бы игрок с этого самого сохранения загружался.
    Что делать?

    По-дефолту, в мейкере 20 слотов сохранений.
    Но сохранять вручную, скриптом, можно в любой слот, даже 20+...То есть сохранить в 21-й слот!
    Спойлер Код для ручнуго сохранения в нужный слот, для "Скрипта":

    Код:
    $gameSystem.onBeforeSave();
    DataManager.saveGame(W);
    где:
    [B]W[/U] - номер файла сохранения, например 21.

    В результате, мейкер будет "видеть", что есть файл сохранения и возможность загрузиться, но в перечне сохранок выводить не будет.

    И на всякий случай, и для того чтоб "туториал" был полным, также код ручной загрузки сохранения - но он может корректно не отрабатывать.
    Спойлер Код для ручнуй загрузки из нужного слота, для "Скрипта":

    Код:
    if (DataManager.loadGame(K)) {
    	$gamePlayer.reserveTransfer($gameMap.mapId(), $gamePlayer.x, $gamePlayer.y);
    	$gamePlayer.requestMapReload();
    	SceneManager.goto(Scene_Map);
    }
    где:
    K - номер файла сохранения, например 1.


    И интересный момент, по ссылки сайт, который может редактировать сохранений мукера MZ:
    https://www.save-editor.com/tools/rp...l_mz_save.html

    P.S:
    Но для таких действий, конечно, лучше использовать плагины.
    Однако, кое-что можно и без них.
    Последний раз редактировалось Darchan Kaen; 19.04.2022 в 15:36. Причина: contеnts не нужен, удален из кода

  2. #2
    Создатель Аватар для Рольф
    Информация о пользователе
    Регистрация
    14.04.2008
    Адрес
    Южно- Сахалинск/Пенза
    Сообщений
    10,283
    Записей в дневнике
    2
    Репутация: 108 Добавить или отнять репутацию

    По умолчанию

    Пропустил как-то пост. Полезно. Спасибо. Особенно сайт с расшифровкой сохранений. Еще можете почитать про автосохранения у меня. Настройка и плагин.
    Последний раз редактировалось Рольф; 26.07.2022 в 14:55.

  3. #3
    Маститый Аватар для Рыб
    Информация о пользователе
    Регистрация
    12.11.2008
    Адрес
    [ДАННЫЕ УДАЛЕНЫ]
    Сообщений
    1,421
    Записей в дневнике
    50
    Репутация: 55 Добавить или отнять репутацию

    По умолчанию

    Размышления на тему

    Про удаление сохранений:
    - Для инвалидации `_globalInfo` можно использовать метод `DataManager.removeInvalidGlobalInfo(); и следом`DataManager.saveGlobalInfo` - для записи в файл "очищенного" файлаа

    Про частичную загрузку
    Опять наверное правильных подход все же зависит для чего использовать доп.инфу)
    Но данных опять же можно просто "прокинуть" в global сохранение. И это звучит чуть логичнее, с той стороны что на базе Global'a у нас обрисовывается окно загрузки и информация(по сути это аналог headers из мукеров VX XP и прочих).

    ЗЫ максимальное количество сохранений в редакторе вообще контролируется вот функцией)
    Код:
    DataManager.maxSavefiles = function() {
        return 20;
    };
    но это опять же проблематика "для плагина"
    Twitch <- Тут иногда делаю вид, что умею играть или работать, в прямом эфире
    GitLab <- Тут иногда делаю вид, что умею программировать
    Github <- Еще какая-то дичь, тут иногда появляется, но с мукером не связана
    Notion<- Тут иногда делаю вид что умею планировать

  4. #4
    Местный Аватар для id0
    Информация о пользователе
    Регистрация
    22.05.2013
    Адрес
    Москва
    Сообщений
    113
    Записей в дневнике
    4
    Репутация: 6 Добавить или отнять репутацию

    По умолчанию

    А как сделать первый слот зарезервированным для автосейва, чтобы игрок не мог в него сохраняться? Ну чтоб он был серенький такой - пубум. Но загружаться мог?
    Спойлер Мои игры на RpgMaker:

  5. #5
    Создатель Аватар для Рольф
    Информация о пользователе
    Регистрация
    14.04.2008
    Адрес
    Южно- Сахалинск/Пенза
    Сообщений
    10,283
    Записей в дневнике
    2
    Репутация: 108 Добавить или отнять репутацию

    По умолчанию

    Ты про МВ? Потому что в МЗ это по умолчанию. Просто в теме речь про Мз.

  6. #6
    Местный Аватар для id0
    Информация о пользователе
    Регистрация
    22.05.2013
    Адрес
    Москва
    Сообщений
    113
    Записей в дневнике
    4
    Репутация: 6 Добавить или отнять репутацию

    По умолчанию

    А точно, сорян. Ну да, я про МВ.
    Спойлер Мои игры на RpgMaker:

  7. #7
    Бывалый Аватар для Darchan Kaen
    Информация о пользователе
    Регистрация
    17.06.2013
    Адрес
    Одесса
    Сообщений
    851
    Записей в дневнике
    3
    Репутация: 47 Добавить или отнять репутацию

    По умолчанию

    Цитата Сообщение от id0 Посмотреть сообщение
    А точно, сорян. Ну да, я про МВ.
    Я это делал плагином:
    https://rpgmaker.su/f109/&#91;mv-mz]dkr_...aveload-4748//

  8. #8
    Местный Аватар для id0
    Информация о пользователе
    Регистрация
    22.05.2013
    Адрес
    Москва
    Сообщений
    113
    Записей в дневнике
    4
    Репутация: 6 Добавить или отнять репутацию

    По умолчанию

    Цитата Сообщение от Darchan Kaen Посмотреть сообщение
    Я это делал плагином:
    https://rpgmaker.su/f109/[mv-mz]dkr_forcedsaveload-4748//
    Дело в том, что у меня уже есть один плагин на сохранения, я боюсь, что будут конфликты. Я хочу в этом конкретно плагине исправить, чтобы первый слот был недоступен. Автосейвы я и вручную делал, они работали прекрасно, а вот какие строчки отвечают за сохранение из меню?
    Спойлер Мои игры на RpgMaker:

  9. #9
    Бывалый Аватар для Darchan Kaen
    Информация о пользователе
    Регистрация
    17.06.2013
    Адрес
    Одесса
    Сообщений
    851
    Записей в дневнике
    3
    Репутация: 47 Добавить или отнять репутацию

    По умолчанию

    Цитата Сообщение от id0 Посмотреть сообщение
    Дело в том, что у меня уже есть один плагин на сохранения, я боюсь, что будут конфликты. Я хочу в этом конкретно плагине исправить, чтобы первый слот был недоступен. Автосейвы я и вручную делал, они работали прекрасно, а вот какие строчки отвечают за сохранение из меню?
    По поводу совместимости ты прав.
    Для того, чтоб это сделать, я чуть модифицировал "дефолтный код" MV, если правильно помню, то за доступность и цвет слота сохранения отвечает вот эти фрагменты кода:

    Спойлер код:

    Код из плагина, с куском моей логики - вырывай её, если не нужна.
    Для большего понимания посмотри .js-файлы MV.

    Смысл в том, что на экране сохранения:
    1) При нажатии на слот движок (Сцена сохранения) должен проверять, доступен ли слот для сохранения.
    2) Если слот недоступен, движок (Окно сцены сохранения) отрисовывает его другим - серым - цветом.
    MV этого не делает, я основывался на подходе MZ.

    Код:
    //----MODIFY CORE-LIB //--РАСШИРЕНИЕ СТАНДАРТНОГО ФУНКЦИОНАЛА
    //--save process //--ДОСТУПНОСТЬ СЛОТА ДЛЯ СОХРАНЕНИЯ
    Scene_Save.prototype.onSavefileOk = function() {
        Scene_File.prototype.onSavefileOk.call(this);
    	
    	let savefileId =  this.savefileId();
    	
    	if( true === isSavefileEnabled(savefileId) ){
    		$gameSystem.onBeforeSave();
    		if (DataManager.saveGame(this.savefileId())) {
    			this.onSaveSuccess();
    			
    			let saveSlotsStatusesList = $gameVariables.value(saveSlotsStatusesListVarId) || [];
    			saveSlotsStatusesList.push( {slotId: savefileId, slotEnabled: true} );
    			$gameVariables.setValue(saveSlotsStatusesListVarId, saveSlotsStatusesList);
    			
    			//saveSlotsStatusesList.push( {slotId: savefileId, slotEnabled: true} );
    		} else {
    			this.onSaveFailure();
    		}
    	} else {
    		this.onSaveFailure();
    	}
        
    };
    
    
    //--save GUI //--ЦВЕТ СЛОТА ИСХОДЯ ИЗ ДОСТУПНОСТИ
    Window_SavefileList.prototype.drawItem = function(index) {
        var id = index + 1;
        var valid = DataManager.isThisGameFile(id);
    	
    	valid = isSavefileEnabled(id);
    	
        var info = DataManager.loadSavefileInfo(id);
        var rect = this.itemRectForText(index);
        this.resetTextColor();
        if (this._mode === 'load') {
            this.changePaintOpacity(valid);
        }
        this.drawFileId(id, rect.x, rect.y);
        if (info) {
            this.changePaintOpacity(valid);
            this.drawContents(info, rect, valid);
            this.changePaintOpacity(true);
        }
    };


    upd:
    Наверное, самый быстрый вариант для твоего плагина - контролировать доступность записи по savefileId в Scene_Save.prototype.onSavefileOk.
    Последний раз редактировалось Darchan Kaen; 28.07.2022 в 10:40.

  10. #10
    Маститый Аватар для Рыб
    Информация о пользователе
    Регистрация
    12.11.2008
    Адрес
    [ДАННЫЕ УДАЛЕНЫ]
    Сообщений
    1,421
    Записей в дневнике
    50
    Репутация: 55 Добавить или отнять репутацию

    По умолчанию

    Цитата Сообщение от id0 Посмотреть сообщение
    А как сделать первый слот зарезервированным для автосейва, чтобы игрок не мог в него сохраняться? Ну чтоб он был серенький такой - пубум. Но загружаться мог?
    Что-то вроде такого попробуй. Если будут ошибки и прочее конфликтов с другими плагинами - пиши

    Код:
    /*:
     * @plugindesc ProtectedSaveSlot
     * @author F15H
     *
     * @help  save this code as `js/plugins/ProtectedSaveSlot.js' for current plugin work || Для корректной работы плагина сохрани в код как `js/plugins/ProtectedSaveSlot.js`
     * @param disabledSaveSlotDisplayName
     * @desc The name for the file that will be displayed for disabled save slot || Отображамое имя для слота, в который запрежено сохранение
     * @type Text
     * @min 0
     * @default Autosave
     *
     * @param disabledSaveSlotIndex
     * @desc Slot number where saving is prohibited || Номер слота, в котором запрещено сохранение
     * @type Number
     * @min 0
     * @default 0
     */
    (function (){
    
        function toNumber(str, def) {
            return isNaN(str) ? def : +(str || def);
        }
        var PARAMS = PluginManager.parameters('ProtectedSaveSlot');
        var disabledSaveSlotIndex = toNumber(PARAMS['disabledSaveSlotIndex'], 0);
        var disabledSaveSlotDisplayName = PARAMS['disabledSaveSlotDisplayName'] || "autosave";
    
        Window_SavefileList.prototype.drawItem = function(index) {
            var id = index + 1;
            var enabled = true;
            var valid = DataManager.isThisGameFile(id);
            var info = DataManager.loadSavefileInfo(id);
            var rect = this.itemRectForText(index);
            this.resetTextColor();
            if (this._mode === 'load') {
                this.changePaintOpacity(valid);
            }
            var drawTextFunction = this.drawFileId;
            if (index === disabledSaveSlotIndex) {
                drawTextFunction = this.drawAutosaveFile;
                enabled = false;
            }
            this.changePaintOpacity(enabled && valid);
            drawTextFunction.call(this, id, rect.x, rect.y);
            if (info) {            
                this.drawContents(info, rect, valid);
                this.changePaintOpacity(true);
            }
        };
    
        Window_SavefileList.prototype.drawAutosaveFile = function(id, x, y) {
            this.drawText(disabledSaveSlotDisplayName, x, y, 180);
        };
    
        var Alias_Scene_Save_prototype_onSavefileOk = Scene_Save.prototype.onSavefileOk;
        Scene_Save.prototype.onSavefileOk = function() {
            var savefileId = this.savefileId();
            if (savefileId === (disabledSaveSlotIndex + 1)) {
                return this.onSaveFailure();
            }
            Alias_Scene_Save_prototype_onSavefileOk.call(this);
        };
    })();
    Чтобы нормально подтянулись параметры плагина, назвать файл с кодом `ProtectedSaveSlot.js`
    UPD: Были баги - поправил
    Последний раз редактировалось Рыб; 28.07.2022 в 21:34.
    Twitch <- Тут иногда делаю вид, что умею играть или работать, в прямом эфире
    GitLab <- Тут иногда делаю вид, что умею программировать
    Github <- Еще какая-то дичь, тут иногда появляется, но с мукером не связана
    Notion<- Тут иногда делаю вид что умею планировать

Страница 1 из 2 12 ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Метки этой темы

Социальные закладки

Социальные закладки

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •  
[MZ] Что интересного можно делать с сохранениями